#include "robotjsoni.h"
#include "tmglobaldef.h"

TmJsonEngineThread::TmJsonEngineThread()
{
    m_strJsonPath = "";
    m_nFrameIndex = 0;
    m_bExit = false;
    _load_auto_action("./Config/AutoPlay.json");

    m_pJsonAuto = new TmJsonEngineAuto(this);
    m_pJsonAuto->start();
}

void TmJsonEngineThread::setExit()
{
    m_bExit = true;
    this->terminate();
}

bool TmJsonEngineThread::Load(QString strPath)
{
    if( strPath.length()<1 ){
        return false;
    }
    m_strJsonPath = "";
    // load json file
    m_jsonActionsMap.clear();
    m_jsonClassMap.clear();
    m_jsonCmdMap.clear();

    QFile file( strPath );
    QByteArray bArrJson;
    if( file.open(QIODevice::ReadOnly) ){
        bArrJson = file.readAll();
        file.close();
    }
    QJsonDocument jsDoc;
    QJsonParseError jsError;
    jsDoc = QJsonDocument::fromJson(bArrJson, &jsError);
    if( jsError.error != QJsonParseError::NoError ){
        qDebug()<<"[JSON] Parser json file error!"<<jsError.errorString();
        return false;
    }
    QJsonObject obj = jsDoc.object();
    QStringList strList = obj.keys();
    for( int i=0; i<strList.size(); i++ ){
        QString strName = strList.at(i);
        QJsonObject valObj = obj.value(strName).toObject();
        m_jsonActionsMap.insert(strName, valObj.value("data").toArray());
    }
    for( int i=0; i<strList.size(); i++ ){
        QString strName = strList.at(i);
        QString strNameClass = strName.left(strName.lastIndexOf('_'));
        QMap<QString, QStringList>::const_iterator arryObj = m_jsonClassMap.find(strNameClass);
        QStringList indexList;
        if( arryObj == m_jsonClassMap.end() ){
            indexList = QStringList();
        }else{
            indexList = arryObj.value();
        }
        indexList.append(strName);
        m_jsonClassMap.insert(strNameClass, indexList);
    }

    m_strJsonPath = strPath;
    qDebug()<<"[json] Load file ok!"<<m_strJsonPath;
    return true;
}

void TmJsonEngineThread::CallByName(QString strName)
{
    m_jsonCmdMap.clear();
    QMap<QString, QJsonArray>::const_iterator arryObj = m_jsonActionsMap.find(strName);
    if( arryObj == m_jsonActionsMap.end() ){
        return;
    }
    QJsonArray bArry = arryObj.value();
    for(int i=0; i<bArry.size();i++){
        QJsonObject obj = bArry.at(i).toObject();
        int nTime = obj.value("time").toInt(-1);
        if( nTime != -1 ) {
            m_jsonCmdMap.insert(nTime, obj);
        }
    }
    m_nFrameIndex = 0;
    m_bFrameLoad = true;
}

void TmJsonEngineThread::CallByClass(QString strClassName)
{
    m_jsonCmdMap.clear();
    QMap<QString, QStringList>::const_iterator it = m_jsonClassMap.find(strClassName);
    if( it == m_jsonClassMap.end() ){
        return;
    }
    QStringList strList = it.value();
    int nMaxSize = strList.size();
    if(nMaxSize<1){
        return;
    }
    int nCurRandomIndex = g_nGetRandom(0, nMaxSize-1); // random name
    QJsonArray bArry = m_jsonActionsMap.value(strList[nCurRandomIndex]);
    for(int i=0; i<bArry.size();i++){
        QJsonObject obj = bArry.at(i).toObject();
        int nTime = obj.value("time").toInt(-1);
        if( nTime != -1 ) {
            m_jsonCmdMap.insert(nTime, obj);
        }
    }
    m_nFrameIndex = 0;
    m_bFrameLoad = true;
}

void TmJsonEngineThread::CallByContent(QByteArray strArray)
{
    m_jsonCmdMap.clear();
    //    QByteArray contentDataArray = QByteArray::fromBase64(bBase64);
    QJsonArray bArry = QJsonDocument::fromJson(strArray).array();
    for(int i=0; i<bArry.size();i++){
        QJsonObject obj = bArry.at(i).toObject();
        int nTime = obj.value("time").toInt(-1);
        if( nTime != -1 ) {
            m_jsonCmdMap.insert(nTime, obj);
        }
    }
    m_nFrameIndex = 0;
    m_bFrameLoad = true;
}

void TmJsonEngineThread::Stop()
{
    m_nFrameIndex = 0;
    m_bFrameLoad = false;
}

bool TmJsonEngineThread::IsPlaying()
{
    return (m_nFrameIndex>0?true:false);
}

void TmJsonEngineThread::AutoPlay()
{
    qDebug()<<"[JSON] call AutoPlay.";
    m_pJsonAuto->StartAuto();
}

void TmJsonEngineThread::List(QStringList &strList)
{
    strList = m_jsonActionsMap.keys();
}

void TmJsonEngineThread::_load_auto_action(QString strFilePath)
{
    m_jsonAutoAction.clear();

    QFile file( strFilePath );
    QByteArray bArrJson;
    if( file.open(QIODevice::ReadOnly) ){
        bArrJson = file.readAll();
        file.close();
    }
    QJsonDocument jsDoc;
    QJsonParseError jsError;
    jsDoc = QJsonDocument::fromJson(bArrJson, &jsError);
    if( jsError.error != QJsonParseError::NoError ){
        qDebug()<<"[JSON] Parser auto_action json file error!"<<jsError.errorString();
        return;
    }
    QJsonObject obj = jsDoc.object();
    QStringList strList = obj.keys();
    for( int i=0; i<strList.size(); i++ ){
        QString strName = strList.at(i);
        QJsonObject valObj = obj.value(strName).toObject();
        m_jsonAutoAction.append(valObj.value("data").toArray());
    }
    qDebug()<<"[JSON] Load auto_action file ok!"<<strFilePath;

}

void TmJsonEngineThread::_tm_auto_play()
{
    int nSize = m_jsonAutoAction.size();
    if( nSize < 1 ){
        return;
    }
    // run
    int nIndex = g_nGetRandom(0, nSize-1);
    qDebug()<<"[JSON] auto play action..."<<nSize<<nIndex;
    QJsonArray bArry = m_jsonAutoAction[nIndex];
    for(int i=0; i<bArry.size();i++){
        QJsonObject obj = bArry.at(i).toObject();
        int nTime = obj.value("time").toInt(-1);
        if( nTime != -1 ) {
            m_jsonCmdMap.insert(nTime, obj);
        }
    }
    m_nFrameIndex = 0;
    m_bFrameLoad = true;
}

void TmJsonEngineThread::run()
{

    while(!m_bExit){
        QCoreApplication::processEvents();
        msleep(10);
        // loop
        while(m_bFrameLoad && !m_bExit){
            if( m_jsonCmdMap.empty() ){
                m_nFrameIndex = 0;
                m_bFrameLoad = false;
                continue;
            }
            QCoreApplication::processEvents();
            msleep(95);
            m_nFrameIndex += 1;
            QJsonObject obj = m_jsonCmdMap.take(m_nFrameIndex);
            if( !obj.isEmpty() ){

                // 解析每一个的参数
                QJsonValue objParam;
                QJsonArray objArray;
                // Motor
                // head
                if( obj.contains("Motor.HeadEnable") ){
                    objParam = obj.value("Motor.HeadEnable");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        bool bLR = objArray.at(0).toInt();
                        bool bUD = objArray.at(1).toInt();
                        g_pSerialTh->HeadEnable(bLR, bUD);
                    }
                }
                if( obj.contains("Motor.HeadLrInit") ){
                    g_pSerialTh->HeadLrInit();
                }
                if( obj.contains("Motor.HeadUdInit") ){
                    g_pSerialTh->HeadUdInit();
                }
                if( obj.contains("Motor.HeadLrAngle") ){
                    objParam = obj.value("Motor.HeadLrAngle");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->HeadLrAngle(nAngle, nSpeed);
                    }
                }
                if( obj.contains("Motor.HeadUdAngle") ){
                    objParam = obj.value("Motor.HeadUdAngle");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->HeadUdAngle(nAngle, nSpeed);
                    }
                }
                // left
                if( obj.contains("Motor.HandLEnable") ){
                    objParam = obj.value("Motor.HandLEnable");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        bool bSwing = objArray.at(0).toInt();
                        bool bExpand = objArray.at(1).toInt();
                        g_pSerialTh->HandLEnable(bSwing, bExpand);
                    }
                }
                if( obj.contains("Motor.HandLSwingInit") ){
                    g_pSerialTh->HandLSwingInit();
                }
                if( obj.contains("Motor.HandLExpandInit") ){
                    g_pSerialTh->HandLExpandInit();
                }
                if( obj.contains("Motor.HandLSwingAngle") ){
                    objParam = obj.value("Motor.HandLSwingAngle");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->HandLSwingAngle(nAngle, nSpeed);
                    }
                }
                if( obj.contains("Motor.HandLExpandAngle") ){
                    objParam = obj.value("Motor.HandLExpandAngle");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->HandLExpandAngle(nAngle, nSpeed);
                    }
                }
                // right
                if( obj.contains("Motor.HandREnable") ){
                    objParam = obj.value("Motor.HandREnable");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        bool bSwing = objArray.at(0).toInt();
                        bool bExpand = objArray.at(1).toInt();
                        g_pSerialTh->HandREnable(bSwing, bExpand);
                    }
                }
                if( obj.contains("Motor.HandRSwingInit") ){
                    g_pSerialTh->HandRSwingInit();
                }
                if( obj.contains("Motor.HandRExpandInit") ){
                    g_pSerialTh->HandRExpandInit();
                }
                if( obj.contains("Motor.HandRSwingAngle") ){
                    objParam = obj.value("Motor.HandRSwingAngle");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->HandRSwingAngle(nAngle, nSpeed);
                    }
                }
                if( obj.contains("Motor.HandRExpandAngle") ){
                    objParam = obj.value("Motor.HandRExpandAngle");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->HandRExpandAngle(nAngle, nSpeed);
                    }
                }
                // wheel
                if( obj.contains("Motor.WheelEnable") ){
                    objParam = obj.value("Motor.WheelEnable");
                    bool bEnable = objParam.toInt();
                    g_pSerialTh->WheelEnable(bEnable);
                }
                if( obj.contains("Motor.WheelStop") ){
                    objParam = obj.value("Motor.WheelStop");
                    bool bSlow = objParam.toInt();
                    g_pSerialTh->WheelStop(bSlow);
                }
                if( obj.contains("Motor.WheelRotate") ){
                    objParam = obj.value("Motor.WheelRotate");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nAngle = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->WheelRotate(nAngle, nSpeed);
                    }
                }
                if( obj.contains("Motor.WheelRun") ){
                    objParam = obj.value("Motor.WheelRun");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nDistance = objArray.at(0).toInt();
                        int nSpeed = objArray.at(1).toInt();
                        g_pSerialTh->WheelRun(nDistance, nSpeed);
                    }
                }

                // led
                if( obj.contains("Motor.HeadEye") ){
                    objParam = obj.value("Motor.HeadEye");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nIndexF = objArray.at(0).toInt();
                        int nIndexR = objArray.at(1).toInt();
                        g_pSerialTh->HeadEye(nIndexF, nIndexR);
                    }
                }
                if( obj.contains("Motor.HeadEye2") ){
                    objParam = obj.value("Motor.HeadEye2");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nDelay = objArray.at(0).toInt();
                        bool bR = objArray.at(1).toInt();
                        bool bG = objArray.at(2).toInt();
                        bool bB = objArray.at(3).toInt();
                        g_pSerialTh->HeadEye2(nDelay, bR, bG, bB);
                    }
                }
                if( obj.contains("Motor.HeadEar") ){
                    objParam = obj.value("Motor.HeadEar");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nDelay = objArray.at(0).toInt();
                        bool bR = objArray.at(1).toInt();
                        bool bG = objArray.at(2).toInt();
                        bool bB = objArray.at(3).toInt();
                        g_pSerialTh->HeadEar(nDelay, bR, bG, bB);
                    }
                }
                if( obj.contains("Motor.BodyLed") ){
                    objParam = obj.value("Motor.BodyLed");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        int nDelay = objArray.at(0).toInt();
                        bool bR = objArray.at(1).toInt();
                        bool bG = objArray.at(2).toInt();
                        bool bB = objArray.at(3).toInt();
                        g_pSerialTh->BodyLed(nDelay, bR, bG, bB);
                    }
                }
                if( obj.contains("Motor.TouchSet") ){
                    objParam = obj.value("Motor.TouchSet");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        bool bFlash = objArray.at(0).toInt();
                        int nColor = objArray.at(1).toInt();
                        int nFPS = objArray.at(2).toInt();
                        g_pSerialTh->TouchSet(bFlash, nColor, nFPS);
                    }
                }
                // Audio
                if( obj.contains("Audio.TtsPlay") ){
                    objParam = obj.value("Audio.TtsPlay");
                    QString strTts = objParam.toString();
                    g_pAudioSender->TtsPlay(strTts);
                }
                if( obj.contains("Audio.TtsPlayParams") ){
                    objParam = obj.value("Audio.TtsPlayParams");
                    objArray = objParam.toArray();
                    if( !objArray.empty() ){
                        QString strTxt = objArray.at(0).toString();
                        QString strSpeaker = objArray.at(1).toString();
                        int nSpeed = objArray.at(2).toInt();
                        int nPitch = objArray.at(3).toInt();
                        g_pAudioSender->TtsPlayParams(strTxt, strSpeaker, nSpeed, nPitch);
                    }
                }
                if( obj.contains("Audio.TtsPlayFile") ){
                    objParam = obj.value("Audio.TtsPlayFile");
                    QString strPath = objParam.toString();
                    g_pAudioSender->TtsPlayFile(strPath);
                }
                if( obj.contains("Audio.TtsSetVolume") ){
                    objParam = obj.value("Audio.TtsSetVolume");
                    int nVal = objParam.toInt();
                    g_pAudioSender->TtsSetVolume(nVal);
                }
                if( obj.contains("Audio.TtsStop") ){
                    g_pAudioSender->TtsStop();
                }
                // Media
                if( obj.contains("Audio.MediaPlay") ){
                    objParam = obj.value("Audio.MediaPlay");
                    QString strPath = objParam.toString();
                    g_pAudioSender->MediaPlay(strPath);
                }
                if( obj.contains("Audio.MediaSetVolume") ){
                    objParam = obj.value("Audio.MediaSetVolume");
                    int nVal = objParam.toInt();
                    g_pAudioSender->MediaSetVolume(nVal);
                }
                if( obj.contains("Audio.MediaStop") ){
                    g_pAudioSender->MediaStop();
                }
            }

        }
        m_nFrameIndex = 0;
        m_bFrameLoad = false;
    }
}

RobotJsonI::RobotJsonI()
{
    QString strFileName = g_pSettingCore->value("Json/Default", "").toString();
    g_pJsonEngTh = new TmJsonEngineThread();
    if(strFileName.length()>0){
        g_pJsonEngTh->Load("./Config/"+strFileName);
    }
    g_pJsonEngTh->start();
}

bool RobotJsonI::Load(const std::string &strPath, const Ice::Current &)
{
    return g_pJsonEngTh->Load(QString::fromUtf8(strPath.c_str()));
}

void RobotJsonI::CallByName(const std::string &strName, const Ice::Current &)
{
    g_pJsonEngTh->CallByName(QString::fromUtf8(strName.c_str()));
}

void RobotJsonI::CallByClass(const std::string &strClassName, const Ice::Current &)
{
    g_pJsonEngTh->CallByClass(QString::fromUtf8(strClassName.c_str()));
}

void RobotJsonI::CallByContent(const std::string &strArray, const Ice::Current &)
{
    g_pJsonEngTh->CallByContent(QByteArray(strArray.c_str(),strArray.size()));
}

void RobotJsonI::Stop(const Ice::Current &)
{
    g_pJsonEngTh->Stop();
}

bool RobotJsonI::IsPlaying(const Ice::Current &)
{
    return g_pJsonEngTh->IsPlaying();
}

void RobotJsonI::AutoPlay(const Ice::Current &)
{
    g_pJsonEngTh->AutoPlay();
}

void RobotJsonI::List(Ice::StringSeq &strList, const Ice::Current &)
{
    QStringList strListOut;
    g_pJsonEngTh->List(strListOut);
    foreach (QString strOne, strListOut) {
        strList.push_back(std::string(strOne.toUtf8().data()));
    }
}

TmJsonEngineAuto::TmJsonEngineAuto(TmJsonEngineThread *pThread)
{
    m_pThread = pThread;
    m_bStart = false;
}

void TmJsonEngineAuto::StartAuto()
{
    m_bStart = true;
}

void TmJsonEngineAuto::StopAuto()
{
    m_bStart = false;
}

void TmJsonEngineAuto::run()
{
    int nLoopCount = 0;
    while(!m_pThread->m_bExit){
        QCoreApplication::processEvents();
        msleep(10);
        if( !m_bStart ){
            nLoopCount = 0;
            continue;
        }
        nLoopCount += 1;
        if( nLoopCount > 90*3){
            nLoopCount = 0;
        }
        if( nLoopCount == 13 ){
            if( g_pAudioSender->TtsIsPlaying() ){
                g_pJsonEngTh->_tm_auto_play();
            }else{
                //g_pJsonEngTh->Stop();
                m_bStart = false;
            }
        }
    }
}
